/**
 * (C)2012 Exlu Corporation. All rights reserved.
 * 文件名 : cn.exlu.wea.mark.test.ExcelTestSupport.java
 * 注意事項   :
 */
package cn.exlu.wea.mark.tools.test.xls;

import static org.junit.Assert.assertEquals;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.After;

import cn.exlu.wea.mark.tools.test.xls.exception.ExcelValueException;
import cn.exlu.wea.mark.tools.test.xls.validator.XlsStringUtil;
import cn.wea.mark.file.excel.ExcelType;
import cn.wea.mark.file.excel.ISheetReader;
import cn.wea.mark.file.excel.exception.SheetNotFoundException;
import cn.wea.mark.file.excel.io.WorkbookReader;

import com.newtouch.mark.exception.NotFileException;
import com.newtouch.mark.xls.common.StringUtil;

/**
 * 使用Excel作为数据源进行测试Java类中的方法
 * @author Mark 
 * @version 1.0.1
 * @CreateTime 2012-12-15
 * ExcelTestSupport.java
 */
public class ExcelTestMethodSupport extends ExcelAbstractTestSupport {
    private int                 FIRST_COLUMN              = 0;               // 第一列序号
    private int                 MAX_COLUMN                = 255;             // EXCEL最大列
    private final static String PARAMETER_LIST_MAP_NAME   = "parameters";    // 参数列表名称
    private final static String PARAMETER_LIST_MAP_PREFIX = "LIST_MAP=";     // 参数列表前缀名称
    private final static String RESULT_LIST_MAP_NAME      = "expectedResult"; // 返回列表名称
    private final static String COMMENT_PREFIX            = "//";

    /**
     * 
     */
    @After
    public void tearDown() {
        try {
            xlsReader.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 构造函数
     */
    public ExcelTestMethodSupport() {
        super();
        try {
            this.xlsReader = new WorkbookReader(new File(getFilePath()), ExcelType.XLS)
                .createISheetReader(0);
        } catch (IOException e) {
            throw new NotFileException(getFilePath() + "文件不存在");
        }
    }

    /**
     * 获取Excel文件目录
     * @return
     */
    private String getFilePath() {
        String pjPath = System.getProperty("user.dir");
        String className = this.getClass().getName().replace(".", "\\");
        return pjPath + "\\test\\java\\" + className + ".xls";
    }

    /**
     * 构造函数
     * @param fileFullPath 文件完全路径
     */
    public ExcelTestMethodSupport(String fileFullPath) {
        super();
        try {
            this.xlsReader = new WorkbookReader(new File(fileFullPath), ExcelType.XLS)
                .createISheetReader(0);
        } catch (IOException e) {
            throw new NotFileException(fileFullPath + "文件不存在");
        }
    }

    /**
     * 构造函数
     * @param xlsReader XlsReader
     */
    public ExcelTestMethodSupport(ISheetReader xlsReader) {
        super(xlsReader);
    }

    /**
     * 设置进行读取EXCEL的Sheet名称
     * @param sheetName 工作表名称
     */
    public void setSheetName(String sheetName) {
        try {
            this.xlsReader.setSheet(sheetName);
        } catch (SheetNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获得参数名称和对应值
     * @param rowNum 行号
     * @param colNumStart 起始列号
     * @param colNumEnd 末了列号
     * @return 参数名称和对应值
     */
    public Map<String, String> getParamterValues(int rowNum, int colNumStart, int colNumEnd) {
        Map<String, String> paramMap = new HashMap<String, String>();
        // 获得参数起始所在行，所在列

        this.xlsReader.getCellValue(rowNum, colNumStart);

        return paramMap;
    }

    /**
     * 获得GROUP ID为[LIST_MAP=parameters]的参数MAP列表
     * @return 方法参数名和值MAP列表
     */
    public List<Map<String, Object>> getParamsListMap() {
        return getListMap(PARAMETER_LIST_MAP_PREFIX, PARAMETER_LIST_MAP_NAME);
    }

    /**
     * 获得GROUP ID为[LIST_MAP=expectedResult]的结果MAP列表
     * @return 方法返回结果MAP列表
     */
    public List<Map<String, Object>> getResultListMap() {
        return getListMap(PARAMETER_LIST_MAP_PREFIX, RESULT_LIST_MAP_NAME);
    }

    /**
     * 获得指定GROUP ID下的参数名和值
     * @param prefix 获取GROUP ID前缀标识符
     * @param groupId GROUP ID
     * @return GROUP ID下的参数名和值
     */
    public List<Map<String, Object>> getListMap(String prefix, String groupId) {
        List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>();
        Map<String, GroupIdEntry> MapGroupIds = getGroupIds(prefix);
        GroupIdEntry groupIdEntry = MapGroupIds.get(prefix + groupId);
        if (groupIdEntry == null) {
            throw new ExcelValueException("找不到指定的GROUP ID。");
        }
        int rowNumKey = groupIdEntry.getRowNum() + 1;
        int colNumKey = groupIdEntry.getColNum();
        int lastRowNum = this.xlsReader.getLastRowNum();
        // 验证是否有第一个参数，若无抛出异常
        if (!isEffectiveValue(rowNumKey)) {
            // 若无参数名，抛出异常
            throw new ExcelValueException("指定的GroupId无参数名。");
        }

        // 验证是否有参数值，首行允许为注释行
        boolean isNotExistVal = true;
        for (int rowNumVal = rowNumKey + 1; rowNumVal <= lastRowNum; rowNumVal++) {
            String val = this.xlsReader.getCellValue(rowNumVal, colNumKey);
            if (StringUtil.isSpaceOrNull(val)) {
                // 如果为空，则认为结束
                break;
            }
            // 若不是,进行有效值判定
            if (isEffectiveValue(rowNumVal)) {
                isNotExistVal = false;
                break;
            }
        }
        if (isNotExistVal) {
            // 若无参数值，抛出异常
            throw new ExcelValueException("指定的GroupId无参数值。");
        }
        int row; // 结束行行号
        int col; // 结束列列号
        // 获得GROUP ID的结束行，和结束列
        for (row = rowNumKey; row <= lastRowNum; row++) {
            if (StringUtil.isSpaceOrNull(this.xlsReader.getCellValue(row, colNumKey))) {
                break;
            }
        }
        for (col = colNumKey; col <= MAX_COLUMN; col++) {
            if (StringUtil.isSpaceOrNull(this.xlsReader.getCellValue(rowNumKey, col))) {
                break;
            }
        }
        ExcelTypeConversion typeConv = new ExcelTypeConversion();
        // 若存在，获得第一行的参数名，即下行的参数值,结束行和结束列以改单元格值为空作为结束点
        for (int i = rowNumKey + 1; i < row; i++) {
            Map<String, Object> map = new HashMap<String, Object>();
            for (int j = colNumKey; j < col; j++) {
                // 获得参数名
                String key = this.xlsReader.getCellValue(rowNumKey, j);
                // 获得值
                String val = this.xlsReader.getCellValue(i, j);
                // 若是有效值
                if (isEffectiveValue(i)) {
                    map.put(key, typeConv.convToObject(val));
                }
            }
            // 若不為空
            if (!map.isEmpty()) {
                listMap.add(map);
            }
        }
        // 获得
        return listMap;
    }

    /**
     * 
     * @param message 信息
     * @param exceptedObj 期望值
     * @param actualObj 实际值
     */
    public void assertObjectEquals(String message, Object exceptedObj, Object actualObj) {
        ExcelTypeConversion typeConv = new ExcelTypeConversion();
        String excepedVal = typeConv.convToString(exceptedObj);
        String actualVal = typeConv.convToString(actualObj);
        assertEquals(message, excepedVal, actualVal);
    }

    /**
     * 获得GROUP ID实例
     * @return
     */
    private Map<String, GroupIdEntry> getGroupIds(String prefix) {
        int firstRowNum = this.xlsReader.getFirstRowNum();
        int lastRowNum = this.xlsReader.getLastRowNum();
        Map<String, GroupIdEntry> mapGroupIds = new HashMap<String, GroupIdEntry>();
        for (int i = firstRowNum; i <= lastRowNum; i++) {
            // 判定是否为空
            String val = this.xlsReader.getCellValue(i, FIRST_COLUMN);

            // 判定是否为有效值
            if (!isEffectiveValue(i)) {
                continue;
            }

            // 判定是否符合指定前缀名称
            if (!val.startsWith(prefix)) {
                continue;
            }
            // 若不为空,且符合指定前缀名称则获得该单元格属性
            GroupIdEntry groupIdEntry = new GroupIdEntry();
            groupIdEntry.setRowNum(i);
            groupIdEntry.setColNum(FIRST_COLUMN);
            groupIdEntry.setValue(val);
            mapGroupIds.put(val, groupIdEntry);
        }
        return mapGroupIds;
    }

    /**
     * 该单元格有效值判定
     * 判定方式：不为空、NULL、所在行注释（注释前缀要写在第一列）
     * 
     * @param str
     * @return
     */
    private boolean isEffectiveValue(int rowNum) {
        String str = this.xlsReader.getCellValue(rowNum, FIRST_COLUMN);
        if (StringUtil.isSpaceOrNull(str)) {
            return false;
        }
        if (XlsStringUtil.isComment(str, COMMENT_PREFIX)) {
            return false;
        }
        return true;
    }

}
